#ifndef __SE_TASKQUEUE_HH__
#define __SE_TASKQUEUE_HH__

#include "MutexLock.hpp"
#include "Thread.hpp"
#include "Condition.hpp"

#include <queue>
#include <memory>

namespace se {

template <typename T>
class TaskQueue {
public:
    TaskQueue(size_t capacity);
    ~TaskQueue();

    /**
     * @brief 添加任务
     * 
     * @param task 
     */
    void push(T task);

    /**
     * @brief 提取任务
     * 
     * @return T 
     */
    T pop();

    /**
     * @brief 判断队列是否为空
     * 
     * @return true 
     * @return false 
     */
    bool empty();

    /**
     * @brief 判断队列是否为满
     * 
     * @return true 
     * @return false 
     */
    bool full();

    /**
     * @brief 唤醒所有在等待的条件
     * 
     */
    void weakup();

private:
    bool _flag;
    size_t _capacity;  // 任务队列的容量
    size_t _size;  // 当前队列的任务数量
    std::queue<T> _queue;  // 任务队列
    MutexLock _mutex;  // 线程锁
    Condition _conditionFull;  // 任务队列满时等待
    Condition _conditionEmpty;  // 任务队列空时等待

};

}  // namespace se

namespace se {

template <typename T>
void TaskQueue<T>::weakup() {
    this->_flag = false;
    this->_conditionEmpty.notifyAll();
}

template <typename T>
TaskQueue<T>::TaskQueue(size_t capacity)
: _flag(true)
, _capacity(capacity)
, _size(0)
, _mutex()
, _conditionFull(_mutex)
, _conditionEmpty(_mutex) { }

template <typename T>
TaskQueue<T>::~TaskQueue() { }

template <typename T>
void TaskQueue<T>::push(T task) {
    MutexLockGuard autoMutex(this->_mutex);
    while (this->full()) {
        this->_conditionFull.wait();
    }

    this->_queue.push(task);
    this->_conditionEmpty.notify();
}

template <typename T>
T TaskQueue<T>::pop() {
    MutexLockGuard AutoMutex(this->_mutex);
    while (this->_flag && this->empty()) {
        this->_conditionEmpty.wait();
    }
    if (this->_flag) {
        T temp = this->_queue.front();
        this->_queue.pop();
        this->_conditionFull.notify();
        return temp;
    } else {
        return T();
    }
}

template <typename T>
bool TaskQueue<T>::empty() { return this->_queue.empty(); }
template <typename T>
bool TaskQueue<T>::full() { return this->_queue.size() == this->_capacity; }

}  // namespace se

#endif
